/***********************************************************************************
 * 文件名： suart_config.h
 * 版本： 2
 * 说明：
 * 	    soft_uart（SUart）配置文件。波特率 = 定时器中断频率 / 3 。
 * 修改记录：
 * 	2021/04/28: 初版。 刘言。
 *  2022/06/06: 新增同步模式；新增 _SUART_INIT_STATE 配置项。
 ***********************************************************************************/
#ifndef _SUART_CONFIG_H_
#define _SUART_CONFIG_H_

// 仅包含需要的文件，polsys驱动和组件接口不需要再包含头文件。
#include <stddef.h>
#ifdef __NO_INCLUDE_PATH    // 如果有，定义在 stddef.h
#include "..\bsp\board.h"
#else
#include "board.h"
#endif


//////// 功能开关

/* 
    定义表示启用同步模式，此模式下的收发API将在接收或者发送1个字节后返回。无事件通知。
    注意：必须在起始位出现后的规定时间内调用接收函数，这个时间是位周期的1/3。实现方案是：
        1. 起始位低电平中断后立即调用循环调用了接收API的协议解析函数。这个IO中断耗时将会非常长。
        2. 起始位低电平中断后立即在主程序中执行上述协议解析函数，RTOS环境中可以利用线程同步机制。
        3. CPU空闲或者休眠，起始位的下降沿唤醒CPU后立即调用上述协议解析函数。
    不启用同步模式时，可以随时接收数据，但是前提是保证调用 SUart_EvTimer 的定时器中断的触发周期的
可靠性。即中断响应时间不能超过位周期的1/3，不能出现过大的累计误差（开启定时器的自动重装载）。
*/
#define _SUART_USE_SYNC_MODE

// 半双工模式，注释掉表示全双工模式
#define _SUART_HALF_DUPLEX

// 启用发送完毕事件通知，注释掉表示关闭
//#define _SUART_USE_TX_DONE_EVENT


//////// 参数设置

/*
初始状态
    异步模式：设置上电时的初始状态，0：等待RX空闲（高电平）后再检测起始位；1：直接检测起始位（低
电平）。需要依据MCU上电时的IO口状态来合理设置避免上电时接收到错误数据。
    同步模式：0：每次接收时先检测并等待是否RX空闲（高电平）后再检测起始位；1：直接检测起始位（低
电平）。如果不能确保起始位发生后及时调用接收API，可以设置为0并将数据包的第一个字节设定为0X00来给
足时间调用接收API，一般可以解决通信偶尔失败的问题。同步模式下通常设置为1.
*/
#define _SUART_INIT_STATE   0

#ifdef _SUART_USE_SYNC_MODE
/*
    同步模式下的接收等待时间，单位是1/3*位周期（_SUart_Wait 中定时器的间隔时间）
    调用 SUart_ReceiveByte 时等待接收超时时间 设为0表示死等。设为1至少会等待11个定时周期，如果
采用循环接收直到收到一整包数据的方式一般需要依据发送方一个数据包中每个字节之间的间隔决定。
    */
    #define _SUART_WAIT_TICK    10
#endif

//////// 设置一些需要引用的外部函数(驱动和组件接口不用再包含头文件)

// 管脚初始化，SUART初始化时被调用，注意 TX 管脚 默认输出逻辑应该为1，否则可能会导致第一个字节发送错误。
#define _SUart_InitPin() // 已在 bsp 中初始化

// 定时器初始化，SUART初始化时被调用，定时器中断频率的 1/3 就是波特率。
#define _SUart_InitTimer() // 已在 soft_pwm 组件中初始化(共用定时器)

// 获取RX脚的电平
#define _SUart_GetRxPin() UART_IO

// 设置TX脚的电平
#define _SUart_SetTxPin(level) UART_IO = level

// 半双工额外需要的切换接口
#ifdef _SUART_HALF_DUPLEX
// 切换成RX脚（输入模式）
#define _SUart_PinRxMode() UART_IO_INPUT_MODE
// 切换成TX脚（输出模式），注意确保切换后立即输出高电平，否则可能会导致第一个字节发送错误。
#define _SUart_PinTxMode() UART_IO_OUTPUT_MODE
#endif

#ifdef _SUART_USE_SYNC_MODE
/*
等待定时器时间到，同时开始计时下一个周期。
    在收发函数中需要的地方会被调用。波特率 = 定时器溢出频率 / 3 。
    注意：当 SUart_ReceiveByte 在中断中被调用时请留意中断嵌套。
*/
#define _SUart_Wait()   \
{\
        while (Tim2_GetIntFlag() == 0); \
        Tim2_ClrIntFlag();             \
}
/*
事件回调（钩子）：开始接收。可定义为空。
    将会在 SUart_ReceiveByte 中被首先调用。
    这里可以做一些确保 _SUart_Wait 中的定时器重新开始计时的操作，正常无需此操作，因为数据包第一个
字节收到起始位触发中断后才调用 SUart_ReceiveByte，此时往往已经过去了一段时间，第一个 _SUart_Wait
未真正等待一个周期反而是好事。
    不要在这里执行耗时的操作，否则错过了起始位接收会出错。
*/
#define _SUart_EvStartReceive()
/*
事件回调（钩子）：停止接收（接收结束，不一定成功）。可定义为空。
    将会在 SUart_ReceiveByte 中返回前调用。
    这里可以做一些状态恢复操作。
    不要在这里执行耗时的操作，否则会影响下一个字节接收。
*/
#define _SUart_EvStopReceive()
/*
事件回调（钩子）：开始发送。可定义为空。
    将会在 SUart_SendByte 中被首先调用。
    这里可以做一些发送前的准备工作。
*/
#define _SUart_EvStartSend()
/*
事件回调（钩子）：完成发送。可定义为空。
    将会在 SUart_SendByte 中返回前调用。
    这里可以做一些状态恢复操作。
*/
#define _SUart_EvStopSend()
/*
事件回调（钩子）：接收出错了。可定义为空。
    e: 错误码，实际上是接收步骤。
    将会在 SUart_ReceiveByte 中被调用。
    当 SUart_ReceiveByte 在中断中被调用时，不要在这里执行耗时的操作。
*/
#define _SUart_EvReceiveError(e) \
{\
    Comm_mError = true;\
}

#endif

#endif
